package com.ruoyi.biz.service;

import java.math.BigDecimal;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.biz.domain.*;
import com.ruoyi.biz.enums.CostTypeEnum;
import com.ruoyi.biz.mapper.BizProjectMapper;
import com.ruoyi.biz.model.req.CostProjectReq;
import com.ruoyi.biz.model.resp.BizCostResp;
import com.ruoyi.biz.model.resp.CostProjectResp;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;

import java.util.stream.Collectors;

import com.ruoyi.system.service.ISysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.biz.mapper.BizCostMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import static com.ruoyi.common.utils.SecurityUtils.getUserId;


/**
 * 成本开支Service业务层处理
 *
 * @author tianl
 * @date 2025-01-01
 */
@Service
public class BizCostService extends ServiceImpl<BizCostMapper, BizCost> {
    @Autowired
    private BizProjectMapper bizProjectMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private BizTrusteeService bizTrusteeService;
    @Autowired
    private BizProjectService bizProjectService;
    @Autowired
    private ProjectQueryService projectQueryService;

    /**
     * 分页查询成本开支
     */
    public IPage<CostProjectResp> listPage(CostProjectReq req) {
        IPage<CostProjectResp> projectPage = projectQueryService.listCost(req);
        List<Long> projectIds = projectPage.getRecords().stream().map(CostProjectResp::getProjectId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(projectIds)) {
            return projectPage;
        }
        List<BizCostResp> costRespList = baseMapper.listByProjectIds(projectIds);
        if (StringUtils.isNotBlank(req.getCostType())) {
            costRespList = costRespList.stream().filter(invoice -> invoice.getCostType().equals(req.getCostType())).collect(Collectors.toList());
        }
        Map<Long, List<BizCostResp>> projectMap = costRespList.stream().collect(Collectors.groupingBy(BizCostResp::getProjectId));
        for (CostProjectResp resp : projectPage.getRecords()) {
            if (projectMap.containsKey(resp.getProjectId())) {
                List<BizCostResp> tmpList = projectMap.get(resp.getProjectId());
                tmpList.sort(Comparator.comparing(BizCost::getCostType));
                BigDecimal total = tmpList.stream().map(BizCostResp::getCostMoney).reduce(BigDecimal.ZERO, BigDecimal::add); // 计算总和
                resp.setCostList(tmpList);
                resp.setCostAmount(total);
            } else {
                resp.setCostList(new ArrayList<>());
                resp.setCostAmount(BigDecimal.ZERO);
            }
        }
        return projectPage;
    }

    /**
     * 查询成本开支列表
     */
    public List<BizCostResp> list(CostProjectReq req) {
        List<CostProjectResp> projectPage = projectQueryService.listAllCost(req);
        List<Long> projectIds = projectPage.stream().map(CostProjectResp::getProjectId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(projectIds)) {
            return new ArrayList<>();
        }
        List<BizCostResp> costRespList = baseMapper.listByProjectIds(projectIds);
        if (StringUtils.isNotBlank(req.getCostType())) {
            costRespList = costRespList.stream().filter(invoice -> invoice.getCostType().equals(req.getCostType())).collect(Collectors.toList());
        }
        return costRespList;
    }

    /**
     * 根据ID查询
     */
    public BizCostResp selectById(Long id) {
        return baseMapper.selectDetail(id);
    }

    /**
     * 新增修改成本开支
     */
    @Transactional(rollbackFor = Exception.class)
    public void beforeSave(BizCost bizCost,Boolean calcProject) {
        if (bizCost.getId() != null) {
            bizCost.setUpdateTime(DateUtils.getNowDate());
        } else {
            bizCost.setCreateTime(DateUtils.getNowDate());
            bizCost.setUpdateTime(DateUtils.getNowDate());
            bizCost.setUserId(getUserId());
        }
        if (bizCost.getProportion() == null) {
            bizCost.setProportion(BigDecimal.ZERO);
        }
        if (bizCost.getCostType().equals(CostTypeEnum.COST_MANAGE_PER.getCode()) || bizCost.getCostType().equals(CostTypeEnum.COST_AGREE_PER.getCode())) {
            bizCost.setReviewUserId(getUserId());
        }
        saveOrUpdate(bizCost);
        if(calcProject) {
            //计算项目成本
            bizProjectService.calcProjectCost(bizCost.getProjectId());
        }
    }

    /**
     * 批量删除成本开支
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(Long[] ids) {
        List<Long> projectIds = new ArrayList<>();
        for (Long id : ids) {
            BizCost bizCost = selectById(id);
            if (bizCost != null) {
                projectIds.add(bizCost.getProjectId());
            }
        }
        baseMapper.deleteBatchIds(Arrays.asList(ids));
        for (Long projectId : projectIds) {
            //计算项目成本
            bizProjectService.calcProjectCost(projectId);
        }
    }

    /**
     * 生成非录入成本
     *
     * @param projectId
     */
    public void calcProjectDefault(Long projectId,Long userId) {
        BizProject project = bizProjectMapper.selectById(projectId);
        if (project == null) {
            throw new ServiceException("无效的项目");
        }
        List<BizCost> costList = baseMapper.listByProjectIdType(projectId, CostTypeEnum.getDefaultCode());
        BizCost costBase = costList.stream().filter(r -> r.getCostType().equals(CostTypeEnum.COST_BASE.getCode())).findFirst().orElse(null);
        BizCost costManage = costList.stream().filter(r -> r.getCostType().equals(CostTypeEnum.COST_MANAGE_PER.getCode())).findFirst().orElse(null);
        BizCost costAgree = costList.stream().filter(r -> r.getCostType().equals(CostTypeEnum.COST_AGREE_PER.getCode())).findFirst().orElse(null);
        BizCost costTax = costList.stream().filter(r -> r.getCostType().equals(CostTypeEnum.COST_TAX.getCode())).findFirst().orElse(null);
        if (costBase == null) {
            costBase = new BizCost();
            costBase.setProjectId(projectId);
            costBase.setCostType(CostTypeEnum.COST_BASE.getCode());
            costBase.setProportion(BigDecimal.ZERO);
            costBase.setCreateTime(DateUtils.getNowDate());
            costBase.setUpdateTime(DateUtils.getNowDate());
            costBase.setUserId(userId);
        }
        if (costManage == null) {
            costManage = new BizCost();
            costManage.setProjectId(projectId);
            costManage.setCostType(CostTypeEnum.COST_MANAGE_PER.getCode());
            costManage.setCostMoney(BigDecimal.ZERO);
            costManage.setCostMoneyOriginal(BigDecimal.ZERO);
            costManage.setStatus(0);
            costManage.setProportion(BigDecimal.ZERO);
            costManage.setCreateTime(DateUtils.getNowDate());
            costManage.setUpdateTime(DateUtils.getNowDate());
            costManage.setUserId(userId);
        }
        if (costAgree == null) {
            costAgree = new BizCost();
            costAgree.setProjectId(projectId);
            costAgree.setCostType(CostTypeEnum.COST_AGREE_PER.getCode());
            costAgree.setStatus(0);
            costAgree.setProportion(BigDecimal.ZERO);
            costAgree.setCreateTime(DateUtils.getNowDate());
            costAgree.setUpdateTime(DateUtils.getNowDate());
            costAgree.setUserId(userId);
        }
        if (costTax == null) {
            costTax = new BizCost();
            costTax.setProjectId(projectId);
            costTax.setCostType(CostTypeEnum.COST_TAX.getCode());
            costTax.setProportion(BigDecimal.ZERO);
            costTax.setCreateTime(DateUtils.getNowDate());
            costTax.setUpdateTime(DateUtils.getNowDate());
            costTax.setUserId(userId);
        }
        String valStr = configService.selectConfigByKey("biz.project.cost.proportion");
        BigDecimal proportion = new BigDecimal("0.2");
        if (valStr != null) {
            try {
                proportion = new BigDecimal(valStr);
            } catch (Exception e) {
                log.error("基础成本比例配置有误！！！", e);
            }
        }
        BigDecimal realIncome = BigDecimal.ZERO;
        if (project.getRealIncome() != null) {
            realIncome = project.getRealIncome();
        }

        BigDecimal baseMoney = realIncome.multiply(proportion);
        costBase.setCostMoney(baseMoney);
        costBase.setCostMoneyOriginal(baseMoney);
        saveOrUpdate(costBase);

        costManage.setCostMoney(BigDecimal.ZERO);
        costManage.setCostMoneyOriginal(BigDecimal.ZERO);
        saveOrUpdate(costManage);

        String valStr1 = configService.selectConfigByKey("biz.project.performance.proportion");
        BigDecimal proportion1 = new BigDecimal("0.08");
        if (valStr != null) {
            try {
                proportion1 = new BigDecimal(valStr1);
            } catch (Exception e) {
                log.error("暂估技术绩效比例配置有误！！！", e);
            }
        }
        BigDecimal agreeMoney = realIncome.multiply(proportion1);
        costAgree.setCostMoney(agreeMoney);
        costAgree.setCostMoneyOriginal(agreeMoney);
        saveOrUpdate(costAgree);

        BigDecimal taxMoney = BigDecimal.ZERO;
        if (project.getTrusteeId() != null) {
            BizTrustee trustee = bizTrusteeService.selectById(project.getTrusteeId());
            if (trustee != null) {
                taxMoney = realIncome.multiply(trustee.getTaxProportion());
            }
        }
        costTax.setCostMoney(taxMoney);
        costTax.setCostMoneyOriginal(taxMoney);
        saveOrUpdate(costTax);
    }

    /**
     * 计算绩效
     *
     * @param bizCost
     */
    public void calcProjectPer(BizCost bizCost) {
        BizProject project = bizProjectMapper.selectById(bizCost.getProjectId());
        if (project == null) {
            throw new ServiceException("无效的项目");
        }
        List<BizCost> costList = baseMapper.listByProjectIdType(bizCost.getProjectId(), CostTypeEnum.getDefaultCode());
        BizCost costChannel = costList.stream().filter(r -> r.getCostType().equals(CostTypeEnum.COST_CHANNEL.getCode())).findFirst().orElse(null);
        BigDecimal channelMoney = BigDecimal.ZERO;
        if (costChannel != null) {
            channelMoney = costChannel.getCostMoney();
        }
        String valStr = configService.selectConfigByKey("biz.project.cost.proportion");
        BigDecimal proportion = new BigDecimal("0.2");
        if (valStr != null) {
            try {
                proportion = new BigDecimal(valStr);
            } catch (Exception e) {
                log.error("基础成本比例配置有误！！！", e);
            }
        }
        BigDecimal otherProportion = BigDecimal.ONE.subtract(proportion);
        BigDecimal totalAmount = BigDecimal.ZERO;
        if (project.getTotalAmount() != null) {
            totalAmount = project.getTotalAmount();
        }
        BigDecimal otherCostAmount = totalAmount.subtract(channelMoney).multiply(otherProportion);
        bizCost.setCostMoney(otherCostAmount.multiply(bizCost.getProportion()));
        bizCost.setCostMoneyOriginal(otherCostAmount.multiply(bizCost.getProportion()));
        bizCost.setReviewUserId(getUserId());
        saveOrUpdate(bizCost);
    }

    public void delByProjectId(Long projectId) {
        LambdaQueryWrapper<BizCost> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(i -> i.eq(BizCost::getProjectId, projectId));
        wrapper.and(i -> i.notIn(BizCost::getCostType, CostTypeEnum.COST_OUT.getCode(),CostTypeEnum.COST_TRAVEL.getCode(),CostTypeEnum.COST_OTHER.getCode()));
        remove(wrapper);
    }
}
